import sys
import os
import requests
import json
import re
from datetime import datetime, timedelta
from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout,
                             QHBoxLayout, QListWidget, QTextEdit, QLabel,
                             QPushButton, QSplitter, QFrame, QMessageBox,
                             QLineEdit, QProgressBar, QComboBox)
from PyQt5.QtCore import Qt, QTimer
import threading
import traceback


class StockInfoFinder(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("股票信息查询器")
        self.setGeometry(100, 100, 1200, 800)

        # 初始化DeepSeek API设置
        self.api_url = "https://api.deepseek.com/v1/chat/completions"
        self.api_key = os.environ.get("deepseek_api_key")
        self.model = "deepseek-chat"

        # 存储查询结果
        self.info_list = []
        self.current_stock = ""

        # 用于防止UI冻结的定时器
        self.ui_timer = QTimer(self)
        self.ui_timer.timeout.connect(self.update_ui)
        self.ui_timer.start(100)  # 每100毫秒更新一次UI

        # 存储需要更新的UI状态
        self.ui_status_message = ""
        self.ui_info_list_update = False
        self.ui_info_content = ""
        self.is_processing = False

        # 初始化UI
        self.init_ui()

    def init_ui(self):
        # 创建主窗口部件
        main_widget = QWidget()
        self.setCentralWidget(main_widget)

        # 创建主布局
        main_layout = QVBoxLayout(main_widget)
        main_layout.setContentsMargins(10, 10, 10, 10)

        # 顶部标题
        title_label = QLabel("股票信息查询器")
        title_label.setStyleSheet("font-size: 24px; font-weight: bold; color: #2c3e50;")
        title_label.setAlignment(Qt.AlignCenter)
        title_label.setFixedHeight(50)
        main_layout.addWidget(title_label)

        # 搜索区域
        search_layout = QHBoxLayout()
        search_label = QLabel("输入股票名称:")
        search_label.setStyleSheet("font-size: 16px;")
        self.search_input = QLineEdit()
        self.search_input.setStyleSheet("font-size: 16px; padding: 5px;")
        self.search_input.setPlaceholderText("例如: 阿里巴巴、腾讯、茅台")

        # 时间范围下拉框
        period_label = QLabel("搜索范围:")
        period_label.setStyleSheet("font-size: 16px;")
        self.period_combo = QComboBox()
        self.period_combo.setStyleSheet("font-size: 16px; padding: 5px;")
        self.period_combo.addItems(["最近7天", "最近30天", "最近90天"])
        self.period_combo.setCurrentIndex(1)  # 默认选择30天

        self.search_button = QPushButton("查询")
        self.search_button.setStyleSheet("font-size: 16px; padding: 5px; background-color: #3498db; color: white;")
        self.search_button.clicked.connect(self.search_stock)

        search_layout.addWidget(search_label)
        search_layout.addWidget(self.search_input, 3)
        search_layout.addWidget(period_label)
        search_layout.addWidget(self.period_combo, 1)
        search_layout.addWidget(self.search_button, 1)
        main_layout.addLayout(search_layout)

        # 进度条
        self.progress_bar = QProgressBar()
        self.progress_bar.setTextVisible(False)
        self.progress_bar.setRange(0, 0)  # 不确定模式
        self.progress_bar.setFixedHeight(5)
        self.progress_bar.setVisible(False)
        main_layout.addWidget(self.progress_bar)

        # 添加分割线
        line = QFrame()
        line.setFrameShape(QFrame.HLine)
        line.setFrameShadow(QFrame.Sunken)
        line.setStyleSheet("background-color: #bdc3c7;")
        main_layout.addWidget(line)

        # 内容区域
        content_layout = QVBoxLayout()

        # 创建分割器
        splitter = QSplitter(Qt.Horizontal)

        # 左侧是信息列表
        info_list_widget = QWidget()
        info_list_layout = QVBoxLayout(info_list_widget)

        self.info_list_label = QLabel("相关信息:")
        self.info_list_label.setStyleSheet("font-size: 16px; font-weight: bold; color: #2c3e50;")
        info_list_layout.addWidget(self.info_list_label)

        self.info_listwidget = QListWidget()
        self.info_listwidget.setStyleSheet("font-size: 14px; border: 1px solid #bdc3c7; border-radius: 5px;")
        self.info_listwidget.itemClicked.connect(self.info_selected)
        info_list_layout.addWidget(self.info_listwidget)

        # 右侧是信息详情
        right_widget = QWidget()
        right_layout = QVBoxLayout(right_widget)

        info_content_label = QLabel("详细内容:")
        info_content_label.setStyleSheet("font-size: 16px; font-weight: bold; color: #2c3e50;")
        right_layout.addWidget(info_content_label)

        self.info_content = QTextEdit()
        self.info_content.setReadOnly(True)
        self.info_content.setStyleSheet("font-size: 14px; border: 1px solid #bdc3c7; border-radius: 5px;")
        self.info_content.setPlaceholderText("选择信息标题后将在这里显示详细内容...")
        right_layout.addWidget(self.info_content)

        # 添加左右两部分到分割器
        splitter.addWidget(info_list_widget)
        splitter.addWidget(right_widget)
        splitter.setSizes([400, 800])  # 调整分割比例，详细内容占更多空间

        content_layout.addWidget(splitter)
        main_layout.addLayout(content_layout, 1)  # 1表示stretch因子，会占据所有可用空间

        # 状态指示器
        self.status_label = QLabel("状态: 准备就绪")
        self.status_label.setStyleSheet("font-size: 14px; color: #7f8c8d;")
        main_layout.addWidget(self.status_label)

    def update_ui(self):
        """定时更新UI的槽函数"""
        if self.ui_status_message:
            self.status_label.setText(self.ui_status_message)
            self.ui_status_message = ""

        if self.ui_info_list_update:
            self._update_info_list()
            self.ui_info_list_update = False

        if self.ui_info_content:
            self.info_content.setHtml(self.ui_info_content)
            self.ui_info_content = ""

    def search_stock(self):
        """搜索股票信息的槽函数"""
        stock_name = self.search_input.text().strip()
        if not stock_name:
            QMessageBox.warning(self, "警告", "请输入股票名称")
            return

        # 获取用户选择的搜索时间范围
        period_text = self.period_combo.currentText()
        if "7天" in period_text:
            search_period = 7
        elif "30天" in period_text:
            search_period = 30
        else:
            search_period = 90

        # 保存当前搜索的股票
        self.current_stock = stock_name

        # 禁用搜索按钮并显示进度条
        self.search_button.setEnabled(False)
        self.progress_bar.setVisible(True)
        self.is_processing = True

        # 更新状态
        self.ui_status_message = f"状态: 正在搜索 {stock_name} 的相关信息..."
        self.info_list_label.setText(f"{stock_name} 相关信息:")

        # 清空列表和内容
        self.info_listwidget.clear()
        self.info_content.clear()

        # 启动获取信息的线程
        threading.Thread(target=self._search_stock_thread, args=(stock_name, search_period), daemon=True).start()

    def _search_stock_thread(self, stock_name, search_period):
        """后台线程获取股票信息"""
        try:
            # 获取指定时间范围前的日期
            past_date = (datetime.now() - timedelta(days=search_period)).strftime("%Y-%m-%d")

            # 构建查询提示，明确要求用模型获取信息
            prompt = f"""请列出关于"{stock_name}"股票从{past_date}到今天这{search_period}天内的所有重要信息。

            重点关注:
            1. 股价重大变动和原因
            2. 公司公告或重要新闻事件
            3. 分析师评级变化
            4. 财务报告或业绩预告
            5. 重大合作、并购或战略调整
            6. 行业相关重大政策变化
            7. 市场对该股票的最新看法

            以JSON格式返回，格式为：
            {{
                "info": [
                    {{
                        "title": "信息标题",
                        "date": "发布日期",
                        "source": "信息来源",
                        "summary": "简短摘要(50字以内)"
                    }}
                ]
            }}

            只返回最近{search_period}天的信息，并按日期从新到旧排序。
            确保信息真实可靠，来源于正规财经媒体，并且与该股票直接相关。"""

            # 构建API请求
            headers = {
                "Content-Type": "application/json",
                "Authorization": f"Bearer {self.api_key}"
            }

            # 修改后的payload，移除了无效的web_search工具
            payload = {
                "model": self.model,
                "messages": [{"role": "user", "content": prompt}],
                "temperature": 0.2,
                "response_format": {"type": "json_object"}
                # 移除无效的tools参数
            }

            # 发送API请求
            self.ui_status_message = f"状态: 正在使用DeepSeek搜索 {stock_name} 的重要信息..."

            try:
                response = requests.post(
                    self.api_url,
                    headers=headers,
                    json=payload,
                    timeout=90  # 延长超时时间
                )

                # 检查响应
                if response.status_code == 200:
                    try:
                        data = response.json()
                        content = data["choices"][0]["message"]["content"]

                        # 如果内容以```json开头，需要提取JSON部分
                        if content.strip().startswith("```json"):
                            json_match = re.search(r'```json\s*(.*?)\s*```', content, re.DOTALL)
                            if json_match:
                                content = json_match.group(1)
                            else:
                                content = content.replace("```json", "", 1)
                                if "```" in content:
                                    content = content.split("```")[0]

                        # 尝试解析JSON
                        try:
                            content_json = json.loads(content)
                            # 处理不同的返回格式
                            if isinstance(content_json, dict) and "info" in content_json:
                                self.info_list = content_json["info"]
                            elif isinstance(content_json, list):
                                self.info_list = content_json
                            else:
                                # 尝试从字典中找到信息列表
                                found = False
                                for key, value in content_json.items():
                                    if isinstance(value, list) and len(value) > 0:
                                        self.info_list = value
                                        found = True
                                        break
                                if not found:
                                    self.info_list = [content_json]

                            # 确保info_list是列表
                            if not isinstance(self.info_list, list):
                                self.info_list = [self.info_list]

                            # 标记UI需要更新
                            self.ui_info_list_update = True
                            self.ui_status_message = f"状态: 已获取 {len(self.info_list)} 条关于 {stock_name} 的重要信息"
                        except json.JSONDecodeError as e:
                            self.ui_status_message = f"状态: JSON解析错误 - {str(e)}"
                            print(f"JSON解析错误: {str(e)}")
                            print(f"原始内容: {content[:200]}...")
                    except Exception as e:
                        self.ui_status_message = f"状态: 处理响应失败 - {str(e)}"
                        print(f"处理响应失败: {str(e)}")
                else:
                    self.ui_status_message = f"状态: API错误 {response.status_code}"
                    print(f"API错误: {response.status_code}")
                    print(f"响应内容: {response.text[:200]}...")
            except requests.RequestException as e:
                self.ui_status_message = f"状态: 网络请求失败 - {str(e)}"
                print(f"网络请求失败: {str(e)}")
        except Exception as e:
            self.ui_status_message = f"状态: 获取信息失败 - {str(e)}"
            print(f"获取信息失败: {str(e)}")
            traceback.print_exc()
        finally:
            # 处理完成，更新UI状态
            self.search_button.setEnabled(True)
            self.progress_bar.setVisible(False)
            self.is_processing = False

    def _update_info_list(self):
        """更新信息列表UI"""
        try:
            self.info_listwidget.clear()
            for info in self.info_list:
                if isinstance(info, dict) and 'title' in info:
                    item_text = f"{info['title']}"
                    if 'date' in info and info['date']:
                        item_text += f" ({info['date']})"
                    self.info_listwidget.addItem(item_text)
                else:
                    print(f"无效的信息项: {info}")

            # 如果没有获取到信息，显示提示
            if len(self.info_list) == 0:
                self.info_listwidget.addItem("未找到相关信息，请尝试其他股票名称或扩大搜索范围")
                self.ui_status_message = "状态: 未找到相关信息"
        except Exception as e:
            print(f"更新信息列表失败: {str(e)}")
            traceback.print_exc()

    def info_selected(self, item):
        """信息选中的槽函数"""
        try:
            # 防止正在处理时再次点击
            if self.is_processing:
                return

            index = self.info_listwidget.currentRow()
            if 0 <= index < len(self.info_list):
                selected_info = self.info_list[index]

                # 显示进度条
                self.progress_bar.setVisible(True)
                self.is_processing = True

                # 更新状态
                self.ui_status_message = "状态: 正在获取详细内容..."

                # 启动获取详细内容线程
                threading.Thread(target=self._get_info_content_thread, args=(selected_info,), daemon=True).start()
        except Exception as e:
            self.ui_status_message = f"状态: 选择信息失败 - {str(e)}"
            print(f"选择信息失败: {str(e)}")
            traceback.print_exc()

            # 重置状态
            self.progress_bar.setVisible(False)
            self.is_processing = False

    def _get_info_content_thread(self, info):
        """后台线程获取信息详细内容"""
        try:
            # 构建详细内容提示
            prompt = f"""请提供以下股票相关信息的详细内容:

            标题: {info['title']}
            日期: {info.get('date', '未知')}
            来源: {info.get('source', '未知')}
            股票: {self.current_stock}

            请提供详尽的信息内容，包括但不限于:
            1. 详细的事件描述和背景
            2. 对股价的实际影响或潜在影响
            3. 市场反应和交易量变化
            4. 分析师对此事件的具体评论和预测
            5. 相关背景信息和行业趋势
            6. 后续发展和最新进展

            请以结构化的方式呈现信息，使用小标题分隔不同部分。
            如果有多个相关信息，请整合它们，确保内容全面、准确。
            请尽可能提供具体数据和事实，而不是一般性描述。

            最后，请简要总结此信息的重要性及对投资者的潜在影响。"""

            # 构建API请求
            headers = {
                "Content-Type": "application/json",
                "Authorization": f"Bearer {self.api_key}"
            }

            # 修改后的payload，移除了无效的web_search工具
            payload = {
                "model": self.model,
                "messages": [{"role": "user", "content": prompt}],
                "temperature": 0.3
                # 移除无效的tools参数
            }

            # 发送API请求
            try:
                response = requests.post(
                    self.api_url,
                    headers=headers,
                    json=payload,
                    timeout=60
                )

                # 检查响应
                if response.status_code == 200:
                    try:
                        data = response.json()
                        content = data["choices"][0]["message"]["content"]

                        # 添加标题和元数据
                        formatted_content = f"""
                        <div style="background-color: #f5f5f5; padding: 15px; border-radius: 8px; margin-bottom: 20px; border: 1px solid #e0e0e0;">
                            <h2 style="margin-top: 0; color: #2c3e50;">{info['title']}</h2>
                            <p><strong>日期:</strong> {info.get('date', '未知')}</p>
                            <p><strong>来源:</strong> {info.get('source', '未知')}</p>
                            <p><strong>股票:</strong> {self.current_stock}</p>
                        </div>
                        """

                        # 将Markdown格式转换为HTML
                        content_html = self._markdown_to_html(content)
                        formatted_content += content_html

                        # 更新UI内容
                        self.ui_info_content = formatted_content
                        self.ui_status_message = "状态: 获取详细内容完成"
                    except Exception as e:
                        self.ui_status_message = f"状态: 处理响应失败 - {str(e)}"
                        print(f"处理响应失败: {str(e)}")
                else:
                    self.ui_status_message = f"状态: API错误 {response.status_code}"
                    print(f"API错误: {response.status_code}")
                    print(f"响应内容: {response.text[:200]}...")
            except requests.RequestException as e:
                self.ui_status_message = f"状态: 网络请求失败 - {str(e)}"
                print(f"网络请求失败: {str(e)}")
        except Exception as e:
            self.ui_status_message = f"状态: 获取详细内容失败 - {str(e)}"
            print(f"获取详细内容失败: {str(e)}")
            traceback.print_exc()
        finally:
            # 隐藏进度条
            self.progress_bar.setVisible(False)
            self.is_processing = False

    def _markdown_to_html(self, text):
        """将Markdown转换为HTML"""
        # 处理标题
        text = re.sub(r'^# (.+)$', r'<h1 style="color: #2c3e50; margin-top: 20px; margin-bottom: 10px;">\1</h1>', text,
                      flags=re.MULTILINE)
        text = re.sub(r'^## (.+)$', r'<h2 style="color: #2c3e50; margin-top: 18px; margin-bottom: 8px;">\1</h2>', text,
                      flags=re.MULTILINE)
        text = re.sub(r'^### (.+)$', r'<h3 style="color: #2c3e50; margin-top: 16px; margin-bottom: 8px;">\1</h3>', text,
                      flags=re.MULTILINE)

        # 处理粗体和斜体
        text = re.sub(r'\*\*(.+?)\*\*', r'<strong>\1</strong>', text)
        text = re.sub(r'\*(.+?)\*', r'<em>\1</em>', text)

        # 处理列表
        # 无序列表
        text = re.sub(r'(?m)^[ \t]*[-*][ \t]+(.+)$', r'<li>\1</li>', text)

        # 有序列表
        text = re.sub(r'(?m)^[ \t]*\d+\.[ \t]+(.+)$', r'<li>\1</li>', text)

        # 简单包装列表项
        lines = text.split('\n')
        in_list = False
        result = []

        for line in lines:
            if line.strip().startswith('<li>'):
                if not in_list:
                    in_list = True
                    result.append('<ul style="margin-bottom: 15px;">')
                result.append(line)
            else:
                if in_list:
                    in_list = False
                    result.append('</ul>')
                result.append(line)

        if in_list:
            result.append('</ul>')

        text = '\n'.join(result)

        # 处理段落
        paragraphs = []
        for p in text.split('\n\n'):
            if not p.strip():
                continue
            if not (p.strip().startswith('<h') or p.strip().startswith('<ul') or p.strip().startswith('<li')):
                p = f'<p style="margin-bottom: 10px; line-height: 1.5;">{p}</p>'
            paragraphs.append(p)

        text = '\n'.join(paragraphs)

        return text


def main():
    app = QApplication(sys.argv)
    window = StockInfoFinder()
    window.show()
    sys.exit(app.exec_())


if __name__ == "__main__":
    main()